package ar.fiuba.tp7552.buildadmin.model.builds;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashSet;

import ar.fiuba.tp7552.buildadmin.model.BaseEntity;
import ar.fiuba.tp7552.buildadmin.model.expensas.Cobro;
import ar.fiuba.tp7552.buildadmin.model.expensas.Cuenta;
import ar.fiuba.tp7552.buildadmin.model.expensas.Expensa;
import ar.fiuba.tp7552.buildadmin.model.expensas.Liquidacion;
import ar.fiuba.tp7552.buildadmin.model.expensas.TipoExpensa;

public class Propiedad extends BaseEntity {

	private Integer 		UF;
	private Integer 		nivel;
	private BigDecimal 		dividendo;
	private Integer			orden;
	private TipoPropiedad	tipo;
	
	private	Collection<Liquidacion> liquidaciones = new HashSet<Liquidacion>();
	private	Collection<Cobro> cobros = new HashSet<Cobro>();
	private Cuenta ordinaria = new Cuenta();
	private Cuenta extraordinaria = new Cuenta();
	
	private Responsable	apoderado;
	private Responsable	inquilino;
	private Responsable	propietario = new Responsable();
	
	/**
	 * Actualiza el estado de la cuenta a partir de un cobro.
	 */
	public void actualizarCuenta(Cobro cobro) {
		Cuenta cuenta = this.getCuenta(cobro.getTipo());
		cobro.setNumero(contarPorTipo(this.cobros, cobro.getTipo())+1);
		cobro.setPropiedad(this);
		cuenta.decrementarSaldo(cobro.getMonto());
		cuenta.decrementarIntereses(cobro.getInteres());
		if (cuenta.getSaldoIntereses().compareTo(BigDecimal.ZERO) < 0) {
			cuenta.setSaldoIntereses(BigDecimal.ZERO);
		}
	}
	
	/**
	 * Actualiza el estado de la cuenta a partir de una liquidaci�n.
	 */
	public void actualizarCuenta(Liquidacion liquidacion) {
		Cuenta cuenta = this.getCuenta(liquidacion.getTipo());
		liquidacion.setNumero(contarPorTipo(this.liquidaciones, liquidacion.getTipo())+1);
		liquidacion.setPropiedad(this);
		liquidacion.setDeudaPrevia(cuenta.getSaldoExpensas());
		cuenta.incrementarSaldo(liquidacion.getMonto());
		cuenta.incrementarIntereses(liquidacion.getInteres());
		liquidaciones.add(liquidacion);
		
		liquidacion.setResponsable(this.getResponsable(liquidacion.getTipo()));
		// actualizo los intereses de la liquidaci�n
		// para que incluya los intereses adeudados.
		liquidacion.setInteres(cuenta.getSaldoIntereses());
	}
	
	public Cuenta getCuenta(TipoExpensa tipoExpensa) {
		switch (tipoExpensa) {
			case ORDINARIA:
				return this.ordinaria;
			case EXTRAORDINARIA:
				return this.extraordinaria;
		}
		throw new IllegalArgumentException("Debe especificar el tipo de expensa");
	}
	
	private long contarPorTipo(Collection<? extends Expensa> expensas, TipoExpensa tipo) {
		long cant = 0;
		for (Expensa exp : expensas) {
			if (tipo.equals(exp.getTipo())) {
				cant++;
			}
		}
		return cant;
	}
	
	private Responsable getResponsable(TipoExpensa tipoExpensa) {
		switch (tipoExpensa) {
			case ORDINARIA:
				if (this.inquilino != null) {
					return this.inquilino;
				} else if (this.apoderado != null) {
					return apoderado;
				} else {
					return propietario;
				}
			case EXTRAORDINARIA:
				if (this.apoderado != null) {
					return this.apoderado;
				} else {
					return this.propietario;
				}
		}
		throw new IllegalArgumentException("Se debe especificar e� tipo de expensa");

	}
	
	//~~ getters y setters ===========================================================
	public Integer getNivel() {
		return nivel;
	}
	public void setNivel(Integer nivel) {
		this.nivel = nivel;
	}
	public BigDecimal getDividendo() {
		return dividendo;
	}
	public void setDividendo(BigDecimal dividendo) {
		this.dividendo = dividendo;
	}
	public Integer getOrden() {
		return orden;
	}
	public void setOrden(Integer orden) {
		this.orden = orden;
	}
	public TipoPropiedad getTipo() {
		return tipo;
	}
	public void setTipo(TipoPropiedad tipo) {
		this.tipo = tipo;
	}
	public Responsable getInquilino() {
		return inquilino;
	}
	public Responsable getApoderado() {
		return apoderado;
	}
	public void setApoderado(Responsable apoderado) {
		this.apoderado = apoderado;
	}
	public void setInquilino(Responsable inquilino) {
		this.inquilino = inquilino;
	}
	public Responsable getPropietario() {
		return propietario;
	}
	public void setPropietario(Responsable propietario) {
		this.propietario = propietario;
	}
	public Collection<Liquidacion> getLiquidaciones() {
		return liquidaciones;
	}
	public void setLiquidaciones(Collection<Liquidacion> liquidaciones) {
		this.liquidaciones = liquidaciones;
	}
	public Collection<Cobro> getCobros() {
		return cobros;
	}
	public void setCobros(Collection<Cobro> cobros) {
		this.cobros = cobros;
	}
	public Cuenta getOrdinaria() {
		return ordinaria;
	}
	public void setOrdinaria(Cuenta ordinaria) {
		this.ordinaria = ordinaria;
	}
	public Cuenta getExtraordinaria() {
		return extraordinaria;
	}
	public void setExtraordinaria(Cuenta extraordinaria) {
		this.extraordinaria = extraordinaria;
	}
	public void setUF(Integer uF) {
		UF = uF;
	}
	public Integer getUF() {
		return UF;
	}
}